package rldungeon.help

import net.cyndeline.scalarlib.rldungeon.dgs.{ActivatorResponderAmountResult, ActivatorResponderAmountEstimator, RewardProcessor, ActivatorResponderProcessor}
import scalax.collection.immutable.Graph

/**
 * Adds rewards and activators to room vertices.
 */
class RoomVertexProcessor
  extends ActivatorResponderProcessor[RoomVertex, CorridorEdge]
  with RewardProcessor[RoomVertex, CorridorEdge]
  with ActivatorResponderAmountEstimator[RoomVertex, CorridorEdge] {

  private var nextActivatorResponderId = 0
  private var nextRewardId = 0

  private var responderAmountMainPath: Option[Int] = None
  private var responderAmountOffPath: Option[Int] = None

  /**
   * Adds an activator to a room and a matching responder to an edge,
   * @param room Room to add activator to.
   * @param edge Corridor edge to add responder to.
   * @param graph Graph that the room and edge belongs to.
   * @return A room/edge tuple that has been updated with an activator/responder. The edge should still point to its
   *         original vertices, and not to the updated vertex returned in the tuple.
   */
  override def createActivatorResponder(room: RoomVertex, edge: CorridorEdge[RoomVertex], graph: Graph[RoomVertex, CorridorEdge]): (RoomVertex, CorridorEdge[RoomVertex]) = {
    val updatedRoom = room.addActivator(nextActivatorResponderId)
    val updatedEdge = edge.addResponders(nextActivatorResponderId)
    nextActivatorResponderId += 1
    (updatedRoom, updatedEdge)
  }

  /**
   * Adds a reward to a room vertex.
   * @param room Room to add reward to.
   * @param graph Graph that the room belongs to.
   * @return A copy of the supplied room with a reward added to it.
   */
  override def addReward(room: RoomVertex, graph: Graph[RoomVertex, CorridorEdge]): RoomVertex = {
    val r = room.addReward(nextRewardId)
    nextRewardId += 1
    r
  }

  /**
   * Computes the amount of responder/activator pairs that should be placed on a map. When the amount is
   * reached, the remaining areas are made meaningful using rewards only.
   * @param graph Graph to compute responder amount for. The graph will have its topology computed and pointless
   *              vertices marked as such, but no object-populating productions will have been applied.
   * @return Upper an lower integer bounds to use when randomly selecting the maximum amount of responders to place
   *         on the map.
   */
  override def computeResponderAmount(graph: Graph[RoomVertex, CorridorEdge]): ActivatorResponderAmountResult = {
    val amountMain = responderAmountMainPath.getOrElse { graph.nodes.size }
    val amountOff = responderAmountOffPath.getOrElse { graph.nodes.size }
    ActivatorResponderAmountResult(amountMain, amountMain + 1, amountOff, amountOff + 1)
  }

  def setResponderAmountMainPath(i: Int) { responderAmountMainPath = Option(i) }
  def setResponderAmountOffPath(i: Int) { responderAmountOffPath = Option(i) }

}
